use crate::rtsp::rtp::rtcp::errors::RtcpError;
use crate::rtsp::rtp::rtcp::rtcp_header::RtcpHeader;
use crate::rtsp::rtp::utils::{Marshal, Unmarshal};
use byteorder::BigEndian;
use bytes::BytesMut;
use bytesio::bytes_reader::BytesReader;
use bytesio::bytes_writer::BytesWriter;

// 报告块结构体
#[derive(Debug, Clone, Default)]
pub struct ReportBlock {
    // 同步源标识符（SSRC），用于唯一标识 RTP 会话中的一个源
    pub ssrc: u32,
    // 丢包率的分数部分，以 1/256 为单位，表示自上次报告以来的丢包比例
    pub fraction_lost: u8,
    // 累计丢包数量
    pub cumutlative_num_of_packets_lost: u32,
    // 扩展的最高序列号
    pub extended_highest_seq_number: u32,
    // 到达时间抖动
    pub jitter: u32,
    // 上次发送报告（SR）的 NTP 时间戳的中间 32 位，用于计算延迟
    pub lsr: u32,
    // 自上次发送报告（SR）以来的延迟，以 1/65536 秒为单位
    pub dlsr: u32,
}

impl Unmarshal<&mut BytesReader, Result<Self, RtcpError>> for ReportBlock {
    fn unmarshal(data: &mut BytesReader) -> Result<Self, RtcpError>
    where
        Self: Sized,
    {
        Ok(ReportBlock {
            // 读取 4 字节作为同步源标识符
            ssrc: data.read_u32::<BigEndian>()?,
            // 读取 1 字节作为丢包率的分数部分
            fraction_lost: data.read_u8()?,
            // 读取 3 字节作为累计丢包数量
            cumutlative_num_of_packets_lost: data.read_u24::<BigEndian>()?,
            // 读取 4 字节作为扩展的最高序列号
            extended_highest_seq_number: data.read_u32::<BigEndian>()?,
            // 读取 4 字节作为到达时间抖动
            jitter: data.read_u32::<BigEndian>()?,
            // 读取 4 字节作为上次发送报告的 NTP 时间戳的中间 32 位
            lsr: data.read_u32::<BigEndian>()?,
            // 读取 4 字节作为自上次发送报告以来的延迟
            dlsr: data.read_u32::<BigEndian>()?,
        })
    }
}

impl Marshal<Result<BytesMut, RtcpError>> for ReportBlock {
    fn marshal(&self) -> Result<BytesMut, RtcpError> {
        // 创建一个默认的字节写入器
        let mut writer = BytesWriter::default();

        // 以大端字节序将各字段的数据写入字节写入器
        writer.write_u32::<BigEndian>(self.ssrc)?;
        writer.write_u8(self.fraction_lost)?;
        writer.write_u24::<BigEndian>(self.cumutlative_num_of_packets_lost)?;
        writer.write_u32::<BigEndian>(self.extended_highest_seq_number)?;
        writer.write_u32::<BigEndian>(self.jitter)?;
        writer.write_u32::<BigEndian>(self.lsr)?;
        writer.write_u32::<BigEndian>(self.dlsr)?;

        // 提取字节写入器中的当前字节数据并返回
        Ok(writer.extract_current_bytes())
    }
}

// RTCP 接收报告结构体
#[derive(Debug, Clone, Default)]
pub struct RtcpReceiverReport {
    // RTCP 通用头
    pub header: RtcpHeader,
    // 发送方的同步源标识符
    pub ssrc: u32,
    // 报告块的向量，每个报告块包含了对一个特定同步源的接收统计信息
    pub report_blocks: Vec<ReportBlock>,
}

impl Unmarshal<BytesMut, Result<Self, RtcpError>> for RtcpReceiverReport {
    fn unmarshal(data: BytesMut) -> Result<Self, RtcpError>
    where
        Self: Sized,
    {
        // 创建一个字节读取器，用于从可变字节缓冲区中读取数据
        let mut reader = BytesReader::new(data);

        // 创建一个 RtcpReceiverReport 实例，并从字节读取器中依次读取各部分数据进行初始化
        let mut receiver_report = RtcpReceiverReport {
            // 调用 RtcpHeader 的 unmarshal 方法解析 RTCP 头部
            header: RtcpHeader::unmarshal(&mut reader)?,
            // 以大端字节序读取 4 字节作为发送方的 SSRC
            ssrc: reader.read_u32::<BigEndian>()?,
            // 其他字段使用默认值
            ..Default::default()
        };

        // 根据 RTCP 头部中的报告计数，循环读取相应数量的报告块
        for _ in 0..receiver_report.header.report_count {
            // 调用 ReportBlock 的 unmarshal 方法解析报告块
            let report_block = ReportBlock::unmarshal(&mut reader)?;
            // 将解析得到的报告块添加到报告块向量中
            receiver_report.report_blocks.push(report_block);
        }

        // 返回解析成功的 RtcpReceiverReport 实例
        Ok(receiver_report)
    }
}

impl Marshal<Result<BytesMut, RtcpError>> for RtcpReceiverReport {
    fn marshal(&self) -> Result<BytesMut, RtcpError> {
        // 创建一个默认的字节写入器
        let mut writer = BytesWriter::default();

        // 调用 RtcpHeader 的 marshal 方法将 RTCP 头部序列化为字节数据
        let header_bytesmut = self.header.marshal()?;
        // 将序列化后的 RTCP 头部字节数据写入字节写入器
        writer.write(&header_bytesmut[..])?;

        // 以大端字节序将发送方的 SSRC 写入字节写入器
        writer.write_u32::<BigEndian>(self.ssrc)?;

        // 遍历报告块向量
        for report_block in &self.report_blocks {
            // 调用 ReportBlock 的 marshal 方法将报告块序列化为字节数据
            let data = report_block.marshal()?;
            // 将序列化后的报告块字节数据写入字节写入器
            writer.write(&data[..])?;
        }

        // 提取字节写入器中的当前字节数据并返回
        Ok(writer.extract_current_bytes())
    }
}
